import App from "../../App.vue";
import { App as Application, Component, createApp } from "vue";
import { Http } from "../api/http.service";
import { CacheService } from "../cache/cache.service";
// 全局注册`@iconify/vue`图标库
import {
  IconifyIconOffline,
  IconifyIconOnline,
  FontIcon
} from "../../components/icon";
// 自定义指令
import * as directives from "@/directives";
import { useUserHooks } from "../pinia/store/user.store";
import { ISetting } from "../pinia/interface";
import { useMenuHooks } from "../pinia/store/menu.store";
import { useAppHooks } from "../pinia/store/app.store";
import { RouterService } from "../router/route.service";
import { GlobalStoreEnum } from "../pinia/enum";
import { useAclHooks } from "../pinia/store/acl.store";
import { SF, SFItem } from "@/components/sf";
import { ST } from "@/components/st";
import LcTreeSt from "@/components/tree-st/tree-st.vue";
import Crud from "@/components/crud/crud.vue";
import { createPinia } from "pinia";
import { Helper } from "../helper/helper.service";
import { getUserInfo } from "../api/oauth/oauth";
export class Init {
  private app: Application<Element>;

  private static init: Init;

  static of() {
    if (!Init.init) {
      Init.init = new Init();
    }
    return Init.init;
  }
  constructor() {
    this.initApp();
  }

  private throwNoAppError() {
    if (!this.app) {
      throw new Error("请先调用initApp，初始化APP");
    }
  }

  private initApp() {
    this.app = this.app ?? createApp(App);
    /** 初始化的时候先初始化相关路由 */
    RouterService.of().initRouter();
    return this;
  }
  /**
   * 使用PINIA
   */
  setPinia() {
    this.throwNoAppError();
    this.app.use(createPinia());
    return this;
  }

  /**
   * 设置自定义指令
   * @returns
   */
  setDirectives() {
    this.throwNoAppError();
    Object.keys(directives).forEach(key => {
      this.app.directive(key, directives[key]);
    });
    return this;
  }
  /**
   * 注册全局组件
   * @returns
   */
  setCompoent() {
    this.throwNoAppError();
    this.app.component("IconifyIconOffline", IconifyIconOffline);
    this.app.component("IconifyIconOnline", IconifyIconOnline);
    this.app.component("FontIcon", FontIcon);
    // 全局注册按钮级别权限组件
    this.app.component("LcSf", SF);
    this.app.component("LcSt", ST);
    this.app.component("LcTreeSt", LcTreeSt);
    this.app.component("LcSfItem", SFItem);
    this.app.component("LcCrud", Crud);
    return this;
  }

  useComponent(name: string, component: Component) {
    this.app.component(name, component);
    return this;
  }

  /**
   * 注册全局变量
   * @returns
   */
  setGlobal() {
    this.throwNoAppError();
    this.app.config.globalProperties.$helper = Helper;
    this.app.config.globalProperties.$api = Http.of();
    this.app.config.globalProperties.$cache = CacheService.of();
    return this;
  }
  /**
   * 设置APP默认值
   */
  private async setAppValue() {
    const app = useAppHooks();
    const setting = CacheService.of().get<ISetting>(GlobalStoreEnum.APP);
    if (setting) {
      app.setAsyncData(setting.layout, setting);
      app.setThemeLayout(app.getTheme.name);
    }
    window.document.body.setAttribute("layout", app.getLayout);
  }

  private async setRouter() {
    const menuHooks = useMenuHooks();
    if (menuHooks?.menus?.length) {
      RouterService.of().addBackStageRouter(menuHooks.flatMenus);
    }
    await RouterService.of().useTo(this.app).isReady();
  }

  /**
   * 启动
   */
  async onLoad() {
    this.throwNoAppError();
    await this.reload();
    return this.app;
  }

  /** 主要加载一下服务端的配置 */
  async reload() {
    const token = CacheService.of().getToken();
    if (token) {
      const userInfo = await getUserInfo();
      if (userInfo) {
        const menuHooks = useMenuHooks();
        const aclHooks = useAclHooks();
        const userHooks = useUserHooks();
        aclHooks.setAbility(userInfo.acls);
        aclHooks.setRole(userInfo.roles);
        aclHooks.setFull(userInfo.superAdmin);
        userHooks.setUser(userInfo);
        /** 相关权限必须在菜单之前否则会有一定的时间差 */
        menuHooks.setMenu(userInfo.menus || []);
      }
    }
    this.setAppValue();
    /** 由于路由依赖 菜单信息，所以菜单初始化必须在路由之前 */
    await this.setRouter();
  }
}
